package com.myspace.server.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.myspace.server.base.entity.CustomPage;
import com.myspace.server.blog.domain.ArticleArchiveDay;
import com.myspace.server.blog.entity.ArticleDetail;
import com.myspace.server.blog.entity.ArticleCategory;
import com.myspace.server.blog.mapper.ArticleDetailMapper;
import com.myspace.server.blog.mapper.CategoryMapper;
import com.myspace.server.blog.service.ArticleDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ArticleDetailServiceImpl implements ArticleDetailService {

    private ArticleDetailMapper articleDetailMapper;
    private CategoryMapper categoryMapper;

    @Autowired
    public ArticleDetailServiceImpl(ArticleDetailMapper articleDetailMapper, CategoryMapper categoryMapper) {
        this.articleDetailMapper = articleDetailMapper;
        this.categoryMapper = categoryMapper;
    }

    @Override
    public List<Map<String, Object>> getArticleList(CustomPage customPage) {
        List<ArticleDetail> articleDetailList = this.getArticleListOrderedPaged(customPage);
        if (CollectionUtils.isEmpty(articleDetailList)) return null;
        articleDetailList.forEach(a -> a.setArticleContentHeader(this.getContentHeader(a.getArticleContent())));
        Set<Long> categoryIdSet = articleDetailList.stream().map(ArticleDetail::getCategoryId).collect(Collectors.toSet());
        List<ArticleCategory> articleCategoryList = categoryMapper.selectBatchIds(categoryIdSet);
        return buildArticleAndCategoryListResult(articleDetailList, articleCategoryList);
    }

    @Override
    public List<Map<String, Object>> getArticleListByCategory(Long categoryId) {
        List<ArticleDetail> articleDetailList = this.getArticleListByCategoryId(categoryId);
        if (CollectionUtils.isEmpty(articleDetailList)) return null;
        articleDetailList.forEach(a -> a.setArticleContentHeader(this.getContentHeader(a.getArticleContent())));
        ArticleCategory articleCategory = categoryMapper.selectById(categoryId);
        return buildArticleAndCategoryListResult(articleDetailList, new ArrayList<ArticleCategory>() {{ add(articleCategory); }});
    }

    @Override
    public Map<String, Object> getArticleById(Long articleId) {
        ArticleDetail articleDetail = articleDetailMapper.selectById(articleId);
        if (articleDetail == null) return null;
        ArticleCategory articleCategory = categoryMapper.selectById(articleDetail.getCategoryId());
        return buildArticleAndCategoryResult(articleDetail, articleCategory);
    }

    @Override
    public List<ArticleArchiveDay> getArticleArchiveListDay() {
        List<ArticleDetail> articleDetailList = getArticleIdAndCreateTime();
        return archiveArticleListDay(articleDetailList);
    }

    private List<Map<String, Object>> buildArticleAndCategoryListResult(List<ArticleDetail> articleDetailList, List<ArticleCategory> articleCategoryList) {
        List<Map<String, Object>> result = new ArrayList<>();
        Map<Long, ArticleCategory> categoryMap = articleCategoryList.stream().collect(Collectors.toMap(ArticleCategory::getId, Function.identity()));
        articleDetailList.forEach(ad -> result.add(buildArticleAndCategoryResult(ad, categoryMap.get(ad.getCategoryId()))));
        return result;
    }

    private Map<String, Object> buildArticleAndCategoryResult(ArticleDetail articleDetail, ArticleCategory articleCategory) {
        return new HashMap<String, Object>() {{
            put("articleDetail", articleDetail);
            put("category", articleCategory);
        }};
    }

    private String getContentHeader(String content) {
        return content.substring(0, 150);
    }

    private List<ArticleDetail> getArticleListOrderedPaged(CustomPage customPage) {
        IPage<ArticleDetail> page = new Page<>(customPage.getPage(), customPage.getSize());
        LambdaQueryWrapper<ArticleDetail> searchParam = new LambdaQueryWrapper<>();
        searchParam.orderByDesc(ArticleDetail::getCreateTime);
        return articleDetailMapper.selectPage(page, searchParam).getRecords();
    }

    private List<ArticleDetail> getArticleListByCategoryId(Long categoryId) {
        LambdaQueryWrapper<ArticleDetail> searchParams = new LambdaQueryWrapper<>();
        searchParams.eq(ArticleDetail::getCategoryId, categoryId);
        return articleDetailMapper.selectList(searchParams);
    }

    private List<ArticleDetail> getArticleIdAndCreateTime() {
        LambdaQueryWrapper<ArticleDetail> searchParams = new LambdaQueryWrapper<>();
        searchParams.select(ArticleDetail::getId, ArticleDetail::getCreateTime);
        return articleDetailMapper.selectList(searchParams);
    }

    private List<ArticleArchiveDay> archiveArticleListDay(List<ArticleDetail> articleDetailList) {
        Map<LocalDate, Integer> archiveMap = new HashMap<>();
        articleDetailList.forEach(ad -> {
            LocalDate archiveDate = ad.getCreateTime().toLocalDate();
            if (archiveMap.containsKey(archiveDate)) {
                archiveMap.put(archiveDate, archiveMap.get(archiveDate) + 1);
            } else {
                archiveMap.put(archiveDate, 1);
            }
        });

        List<ArticleArchiveDay> articleArchiveDayList = new ArrayList<>();
        archiveMap.forEach((key, value) -> {
            ArticleArchiveDay articleArchiveDay = ArticleArchiveDay.builder().archiveDate(key).articleNum(value).build();
            articleArchiveDayList.add(articleArchiveDay);
        });

        return articleArchiveDayList;
    }

}
